package com.yupi.yupao.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.MapSession;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 会话故障转移配置
 * 提供Redis宕机时的本地会话存储
 */
@Slf4j
@Configuration
@EnableScheduling
public class SessionFailoverConfig {
    
    /**
     * Redis连接状态
     */
    private volatile boolean redisAvailable = true;
    
    /**
     * 本地会话缓存，用于Redis不可用时的降级策略
     */
    private final Map<String, Object> localSessionCache = new ConcurrentHashMap<>();
    
    @Value("${spring.session.timeout:2592000}")
    private int sessionTimeout;
    
    @Bean
    public RedisAvailabilityChecker redisAvailabilityChecker(RedisTemplate<String, Object> redisTemplate) {
        return new RedisAvailabilityChecker(redisTemplate, this);
    }
    
    /**
     * 定时检查Redis可用性
     */
    @Scheduled(fixedRate = 30000) // 每30秒检查一次
    public void checkRedisAvailability() {
        RedisAvailabilityChecker checker = redisAvailabilityChecker(null);
        boolean currentAvailability = checker.isRedisAvailable();
        
        if (currentAvailability != redisAvailable) {
            // Redis状态发生变化
            redisAvailable = currentAvailability;
            if (redisAvailable) {
                log.info("Redis恢复可用，切换回Redis会话存储");
                // Redis恢复后，可以考虑将本地缓存的会话数据迁移回Redis
            } else {
                log.warn("Redis不可用，启动本地会话存储降级方案");
            }
        }
    }
    
    /**
     * 判断是否使用本地缓存
     */
    public boolean shouldUseLocalCache() {
        return !redisAvailable;
    }
    
    /**
     * 从本地缓存获取会话数据
     */
    public Object getFromLocalCache(String sessionId) {
        return localSessionCache.get(sessionId);
    }
    
    /**
     * 存储会话数据到本地缓存
     */
    public void storeInLocalCache(String sessionId, Object sessionData) {
        localSessionCache.put(sessionId, sessionData);
    }
    
    /**
     * 从本地缓存删除会话数据
     */
    public void removeFromLocalCache(String sessionId) {
        localSessionCache.remove(sessionId);
    }
    
    /**
     * Redis可用性检查器
     */
    @Slf4j
    public static class RedisAvailabilityChecker {
        private final RedisTemplate<String, Object> redisTemplate;
        private final SessionFailoverConfig sessionFailoverConfig;
        
        public RedisAvailabilityChecker(RedisTemplate<String, Object> redisTemplate,
                                        SessionFailoverConfig sessionFailoverConfig) {
            this.redisTemplate = redisTemplate;
            this.sessionFailoverConfig = sessionFailoverConfig;
        }
        
        /**
         * 检查Redis是否可用
         */
        public boolean isRedisAvailable() {
            if (redisTemplate == null) {
                return false;
            }
            
            try {
                // 尝试执行一个简单的Redis操作
                String testKey = "redis:availability:test";
                redisTemplate.opsForValue().set(testKey, "test", 1);
                return true;
            } catch (Exception e) {
                log.error("Redis连接检查失败，可能不可用", e);
                return false;
            }
        }
    }
} 